import os
from temp import get_closest_img, get_closest_video, get_target_mp4, flush_target_m3u8
import temp
from flask import request
import time
from json_flask import JsonFlask
from json_response import JsonResponse
from flask_cors import CORS
from config import FILE_PATH, HTTP_PORT, IP, M3U8_PATH, PORT
import threading
from TimedTasks import time_task
from log_utils import get_logger

log = get_logger()
app = JsonFlask(__name__)
CORS(app, origins='*', supports_credentials=True)


record_path = mp4_root_path = FILE_PATH
m3u8_path = M3U8_PATH
# 存储固定时延直播心跳，如果固定时延直播心跳超时，关闭更新m3u8线程和
listen_dict = {}
# 存储m3u8线程
all_thread_list = {}

from datetime import datetime


@app.route('/api/slice/delay/listen', methods=['Post'])
def listen_delay():
    global listen_dict
    """
    固定时延实时直播前端心跳监听
    前端每隔10秒发送一次心跳，后端接收心跳后更新时间，如果超过一分钟不更新心跳，则关闭这个m3u8线程
    :return:
    """
    start_time = time.time()
    temp_dict = request.get_json()
    if "m3u8_path" in temp_dict.keys():
        m3u8_path_temp = temp_dict["m3u8_path"]
        listen_dict[m3u8_path_temp] = int(time.time())


@app.route('/api/slice/delay/stop', methods=['Post'])
def stop_delay():
    """
    固定时延直播停止，前端监听到浏览器关闭或者刷新后，调用关闭接口
    更新监听字典，将时间置0，直接关闭m3u8线程
    """
    temp_dict = request.get_json()
    m3u8_path_temp = temp_dict["m3u8_path"]
    if m3u8_path_temp in all_thread_list.keys():
        listen_dict[m3u8_path_temp] = 0
        temp.stop_list.append(m3u8_path_temp)


@app.route('/api/slice/delay/camera_time', methods=['Post'])
def get_camera_delay():
    global all_thread_list
    """
    固定时延实时直播
    前端请求参数：
    app: 前端拉流代理里面设置的视频应用名
    stream: 前端拉流代理里面设置的视频流
    timeDay: 需要延时播放的视频日期
    newestStamp: 最新的毫秒级时间戳
    timeDiff: 需要延迟的时间（秒）
    
    :return:
    """
    start_time = time.time()
    temp_dict = request.get_json()
    # print(temp_dict)
    log.info(f"固定时延开始请求{temp_dict}")
    app = temp_dict["app"]
    stream = temp_dict["stream"]
    timeDay = temp_dict["timeDay"]
    newestStamp = int(int(temp_dict["newestStamp"]))
    timeDiff = int(temp_dict["timeDiff"])
    history_time = newestStamp

    if app == "" or stream == "" or newestStamp == "" or timeDiff == "" or timeDay == "":
        return JsonResponse.error("参数为空")
    # 如果时延延迟小于10分钟，采用m3u8方式播放，否则，直接播放mp4文件即可
    if timeDiff <= 10 * 60:
        # print("读取m3u8视频")
        raw_m3u8_path = m3u8_path + "/" + app + "/" + stream + "/hls.m3u8"
        target_m3u8_path = m3u8_path + "/" + app + "/" + stream + "/" + str(history_time) + "hls.m3u8"
        http_m3u8_path = "http://" + IP + ":" + PORT + "/" + app + "/" + stream + "/" + str(history_time) + "hls.m3u8"
        time_list = {}
        raw_m3u8 = []
        with open(raw_m3u8_path, "r", encoding="utf-8") as file_log:
            while True:
                line = file_log.readline().strip()  # 读取文件中的数据
                if line:
                    if timeDay in line:
                        # print(line.split("_")[0])
                        time_str = line.split("_")[0]
                        datetime_obj = datetime.strptime(time_str, "%Y-%m-%d/%H/%M-%S")
                        timestamp = int(datetime_obj.timestamp())
                        # print("时间戳",timestamp)
                        time_list[timestamp] = line
                    raw_m3u8.append(line)
                else:
                    break
        min_diff = float('inf')
        closest_timestamp = None

        for timestamp in time_list.keys():
            timestamp_int = int(timestamp)
            diff = abs(timestamp_int - history_time)
            if diff < min_diff:
                min_diff = diff
                closest_timestamp = timestamp
        time_diff = abs(closest_timestamp - history_time)
        log.info(f"时间差为{time_diff}")
        # print(raw_m3u8)
        # print(time_list[closest_timestamp])
        last_line = time_list[list(time_list.keys())[-1]]
        target_line = time_list[closest_timestamp]
        # print("前", raw_m3u8)
        raw_m3u8[5] = '#EXT-X-MEDIA-SEQUENCE:' + target_line.split("_")[1][:-3]
        target_m3u8 = raw_m3u8[:6] + raw_m3u8[raw_m3u8.index(target_line) - 1:]
        # print("后", target_m3u8)
        with open(target_m3u8_path, "w", encoding="utf-8") as f:
            for t in target_m3u8:
                f.write(t + "\n")
        sim_scene_test_tess_process = threading.Thread(target=flush_target_m3u8, args=(
            raw_m3u8_path, target_m3u8_path, last_line, target_m3u8, timeDay, http_m3u8_path, log,))
        sim_scene_test_tess_process.start()
        all_thread_list[http_m3u8_path] = sim_scene_test_tess_process

        log.info(f"第一次调用明m3u8增加心跳{http_m3u8_path}")
        listen_dict[http_m3u8_path] = int(time.time())
        return JsonResponse.success(http_m3u8_path)
    else:
        # print("读取mp4视频")
        mp4_path = mp4_root_path + "/" + app + "/" + stream + "/" + timeDay
        target_file, next_file_lists = get_target_mp4(mp4_path, history_time, timeDay)
        # print(target_file, next_file_lists)
        return {"target_file": target_file, "next_file_lists": next_file_lists,
                "url": IP + ":" + PORT + "/record/" + app + "/" + stream + "/" + timeDay}


@app.route('/api/slice/snap/camera_time/', methods=['Post'])
def get_camera_snap():
    """
    根据毫秒时间戳获得取证图片
    :return:
    """
    start_time = time.time()
    temp_dict = request.get_json()
    app = temp_dict["app"]
    stream = temp_dict["stream"]
    timeDay = temp_dict["timeDay"]
    timeStamp = str(temp_dict["timeStamp"])
    # print("传入的时间为", timeStamp)
    log.info(f"图片取证传入的参数为{temp_dict}")
    if app == "" or stream == "" or timeDay == "" or timeStamp == "":
        return JsonResponse.error("参数为空")

    bin_path = record_path + "/" + app + "/" + stream + "/" + timeDay

    nginx_path = bin_path + "/img/" + timeStamp + ".jpg"
    result = "http://" + IP + ":" + PORT + "/record" + "/" + app + "/" + stream + "/" + timeDay + "/img/" + timeStamp + ".jpg"
    # if os.path.exists(nginx_path):
    # return JsonResponse.success(result)

    if not os.path.isdir(bin_path + "/img"):
        os.makedirs(bin_path + "/img")
    # 根据传入的时间戳生成取证图片
    img_nginx_path = get_closest_img(bin_path, timeStamp, nginx_path)
    if img_nginx_path is None:
        return JsonResponse.error("数据暂未生成，请稍后")
    log.info(f"图片取证耗时{time.time() - start_time}")
    return JsonResponse.success(result)


@app.route('/api/slice/video/camera_time/', methods=['Post'])
def get_camera_video():
    """
    根据毫秒时间戳获得取证图片
    :return:
    """
    start_time = time.time()
    temp_dict = request.get_json()
    # print(temp_dict)
    log.info(f"视频取证传入的参数为{temp_dict}")
    app = temp_dict["app"]
    stream = temp_dict["stream"]
    timeDay = temp_dict["timeDay"]
    startTimeStamp = str(temp_dict["startTimeStamp"])
    endTimeStamp = str(temp_dict["endTimeStamp"])
    if app == "" or stream == "" or timeDay == "" or startTimeStamp == "" or endTimeStamp == "":
        return JsonResponse.error("参数为空")

    bin_path = record_path + "/" + app + "/" + stream + "/" + timeDay

    nginx_path = bin_path + "/img/" + startTimeStamp + "_" + endTimeStamp + ".mp4"
    result = "http://" + IP + ":" + PORT + "/record" + "/" + app + "/" + stream + "/" + timeDay + "/img/" + startTimeStamp + "_" + endTimeStamp + ".mp4"

    if os.path.exists(nginx_path):
        return JsonResponse.success(result[:-4] + "copy" + result[-4:])

    if not os.path.isdir(bin_path + "/img"):
        os.makedirs(bin_path + "/img")

    img_nginx_path = get_closest_video(bin_path, startTimeStamp, endTimeStamp, nginx_path,log)
    log.info(f"视频取证耗时{time.time() - start_time}")
    return JsonResponse.success(result[:-4] + "copy" + result[-4:])


@app.errorhandler(Exception)
def error_handler(e):
    """
    全局异常捕获
    """
    return JsonResponse.error(msg=str(e))


def runstart():
    app.run(host='0.0.0.0', port=HTTP_PORT)


def httpserver():
    runstart()


def listen_delete():
    global listen_dict, all_thread_list
    while True:
        try:
            current_time = int(time.time())
            delete_list = []
            for k, v in listen_dict.items():
                if (current_time - v) >= 60:
                    delete_list.append(k)
                    log.info(f"{k}过期，加入删除列表，判断是否删除")
                    # print(k, "过期删除")
                    # temp.stop_list.append(k)
                    if k in all_thread_list.keys():
                        log.info(f"{k}过期，进程关闭")
                        temp.stop_list.append(k)
                    else:
                        log.error(f"{k}不在进程字典里面")

            for d in delete_list:
                if d in listen_dict.keys() and d in all_thread_list.keys():
                    if not all_thread_list[d].is_alive():
                        del listen_dict[d]
                else:
                    del listen_dict[d]
            # print("存活的线程", listen_dict)
            # log.info(f"前端心跳上报视频信息{listen_dict}")
            count = 0
            delete_list_thread = []
            for k, v in all_thread_list.items():
                if v.is_alive():
                    count += 1
                else:
                    log.info(f"线程{k}关闭")
                    delete_list_thread.append(k)
            for d in delete_list_thread:
                del all_thread_list[d]
            log.info(f"存活进程数为{count}")
            time.sleep(10)
        except Exception as e:
            log.info(f"监听删除异常{e}")
            time.sleep(10)
            continue


if __name__ == '__main__':
    # 定时删除过期视频线程缓存
    threading.Thread(target=time_task,args=()).start()
    # 监听固定时延直播心跳线程
    threading.Thread(target=listen_delete).start()
    # http服务
    httpserver()
